package ca.turbulent.text
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.CapsStyle;
	import flash.display.Graphics;
	import flash.display.JointStyle;
	import flash.display.LineScaleMode;
	import flash.display.MovieClip;
	import flash.display.PixelSnapping;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.geom.Rectangle;
	import flash.text.AntiAliasType;
	import flash.text.CSMSettings;
	import flash.text.Font;
	import flash.text.FontStyle;
	import flash.text.FontType;
	import flash.text.GridFitType;
	import flash.text.StaticText;
	import flash.text.StyleSheet;
	import flash.text.TextColorType;
	import flash.text.TextDisplayMode;
	import flash.text.TextExtent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.text.TextLineMetrics;
	import flash.text.TextRenderer;
	import flash.text.TextSnapshot;

	public class SuperText extends Sprite
	{
		public static const ANTI_ALIAS_ADVANCED		:String = AntiAliasType.ADVANCED;
		public static const ANTI_ALIAS_NORMAL		:String = AntiAliasType.NORMAL;
		
		public static const BACKGROUND_NORMAL		:String = "backgroundNormal";
		public static const BACKGROUND_ADVANCED		:String = "backgroundAdvanced";
		
		public static const GRID_PIXEL_FIT			:String = GridFitType.PIXEL;
		public static const GRID_PIXEL_NONE			:String = GridFitType.NONE;
		public static const GRID_PIXEL_SUB			:String = GridFitType.SUBPIXEL;
		
		public static const H_ALIGN_LEFT			:String = TextFormatAlign.LEFT;
		public static const H_ALIGN_CENTER			:String = TextFormatAlign.CENTER;
		public static const H_ALIGN_RIGHT			:String = TextFormatAlign.RIGHT;
		
		public static const V_ALIGN_TOP				:String = "top" 
		public static const V_ALIGN_BOTTOM			:String = "bottom";
		public static const V_ALIGN_MIDDLE			:String = "middle"; 
		 
		public var background_mc					:Sprite = new Sprite();
		public var highLites_mc						:Sprite = new Sprite();
		public var autoRedrawBackground				:Boolean = true;
		public var maxWidth							:Number = 150;
		public var minWidth							:Number = 80;
		public var minHeight						:Number = 50;
		
		private var _hAlignMode						:String = SuperText.H_ALIGN_LEFT; 
		private var _vAlignMode						:String = SuperText.V_ALIGN_TOP;
		
		private var _isInteractive					:Boolean = false;
		private var _wordWrap						:Boolean = true;
		
		private var _antiAliasType					:String = AntiAliasType.NORMAL;
		private var _autoSize 						:Boolean = false;
		private var _autoScroll						:Boolean = false;
		
		private var _backgroundColor				:Number = 0x666666;
		private var _backgroundOutlineColor			:Number = 0x333333;
		private var _backgroundOutlineAlpha			:Number = 0;
		private var _backgroundOutlineThickness		:Number = .5;
		private var _backgroundAlpha				:Number = 1;
		private var _backgroundFilters				:Array = new Array();
		private var _backgroundType					:String = SuperText.BACKGROUND_NORMAL;
		
		private var _hasBackground					:Boolean = false;
		private var pixelGridSettings				:String = GridFitType.NONE;
		
		private var _textField						:TextField; 
		private var _textFormat						:TextFormat = new TextFormat();
		
		
		/**
		 * 
		 * @param w
		 * @param h
		 * @param baseTF
		 * 
		 */		
		public function SuperText(w:Number=150, h:Number=50, baseTF:TextFormat=null)
		{
			super();
			initializeText(w, h, baseTF);
		}
		
		
		/**
		 * 
		 * @param w
		 * @param h
		 * @param baseTF
		 * 
		 */		
		private function initializeText(w:Number, h:Number, baseTF:TextFormat=null):void
		{
			maxWidth = w;
			minHeight = h;
			
			_textField = new TextField();
			_textField.width = maxWidth;
			_textField.height = minHeight;
			
			if (baseTF)
			{
				_textField.defaultTextFormat = baseTF;
				_textFormat = baseTF;
				_textField.embedFonts = true;			
			}
			
			
			addChild(_textField);
		}
		
		/**
		 * 
		 * 
		 */		
		public function alignCenter():void 
		{ 
			_textFormat.align = TextFormatAlign.CENTER; 
			redraw();
		}
		
		/**
		 * 
		 * 
		 */		
		public function alignLeft():void 
		{ 
			_textFormat.align = TextFormatAlign.LEFT; 
			redraw();	
		}
		
		/**
		 * 
		 * 
		 */		
		public function alignRight():void 
		{ 
			_textFormat.align = TextFormatAlign.RIGHT; 
			redraw();
		}
		
		/**
		 * 
		 * 
		 */		
		public function alignMiddle():void
		{
			
		}
		
		/**
		 * 
		 * 
		 */		
		public function alignTop():void
		{
			
		}
		
		/**
		 * 
		 * 
		 */		
		public function alignBottom():void
		{
			
		}
		
		public function appendText(textMsg:String, newline:Boolean=true, formatObj:Object=null):void
		{
			_textField.htmlText += textMsg;
			redraw();
		}
		
		public function appendHTMLText(textMsg:String, newline:Boolean=true, formatObj:Object=null):void
		{
			_textField.htmlText += textMsg;
			redraw();
		}
		
		public function fitPixelGrid():void {  this.setPixelGrid(SuperText.GRID_PIXEL_FIT); }
		public function fitSubPixelGrid():void { this.setPixelGrid(SuperText.GRID_PIXEL_SUB); }
		public function releasePixelGrid():void { this.setPixelGrid(SuperText.GRID_PIXEL_NONE); }
		
		
		public function getTextAsset():TextField
		{
			return _textField;
		}
		
		public function redraw(refreshTextFormat:Boolean=true):void
		{
			if (contains(_textField))
				removeChild(_textField);
			
			interactive = _isInteractive;
			
			if (refreshTextFormat)
				_textField.setTextFormat(_textFormat);	
			
			setPixelGrid(pixelGridSettings);
			
			if (autoScroll)
				_textField.scrollV = _textField.maxScrollV;
			
			_textField.width = maxWidth;
			
			if (autoSize)
			{
				if (_textField.textWidth < this.minWidth)
					_textField.width = minWidth;
				else if (_textField.textWidth > this.maxWidth)
					_textField.width = maxWidth;
				
			}
			
			addChild(_textField);
			redrawBackground();
		}	
		
		public function redrawBackground():void
		{
			if (this._hasBackground && autoRedrawBackground)
			{
				if (backgroundType == SuperText.BACKGROUND_ADVANCED)
					drawAdvancedBackground();
				else
					drawNormalBackground();				
			}
			else
			{
				this.clearBackgrounds();			
			}
		}
		
		private function setPixelGrid(gridFit:String):void
		{
			if (gridFit == SuperText.GRID_PIXEL_FIT || gridFit == SuperText.GRID_PIXEL_SUB)
			{
				_textField.gridFitType = gridFit;
				_textField.antiAliasType = SuperText.ANTI_ALIAS_ADVANCED;
				pixelGridSettings = gridFit;
			}	
			else
			{
				_textField.gridFitType = SuperText.GRID_PIXEL_NONE;
				_textField.antiAliasType = SuperText.ANTI_ALIAS_NORMAL;
				pixelGridSettings = SuperText.GRID_PIXEL_NONE;
			}
		}	
		
		public static function createTextFormat(fObj:Object):TextFormat
		{
			var tf:TextFormat = new TextFormat();
			for (var e:String in fObj)
			{
				tf[e] = fObj[e];
			}	
			return tf;
		}
		
		public function replaceSelectedText(txtMsg:String):void
		{
			_textField.replaceSelectedText(txtMsg);
		}
		
		
		public function resize(w:Number, h:Number):void
		{
			_textField.width = w;
			_textField.height = h;
			redraw();
		}
		
		public function setSelectedText(startIndex:int, endIndex:int):void
		{
			_textField.setSelection(startIndex, endIndex);
		}
		
		
		public function set antiAliasType(type:String):void
		{
			if (type == SuperText.ANTI_ALIAS_ADVANCED || type == SuperText.ANTI_ALIAS_NORMAL)
				_textField.antiAliasType = type;
		}
		
		public function set autoSize(auto:Boolean):void
		{
			_autoSize = auto;
			if (auto)
			{
				switch (this.textFormat.align)
				{
					case TextFormatAlign.LEFT:
					default:
					
					_textField.autoSize = TextFieldAutoSize.LEFT;
					break;
					
					case TextFormatAlign.RIGHT:
					_textField.autoSize = TextFieldAutoSize.RIGHT;
					break;
					
					case TextFormatAlign.CENTER:
					_textField.autoSize = TextFieldAutoSize.CENTER;
					break;
					
					case TextFormatAlign.JUSTIFY:
					_textField.autoSize = TextFieldAutoSize.NONE;
					break
				
					
				}
			}
		}
		
		public function get autoSize():Boolean
		{
			return _autoSize;
		}
		
		public function set hasBackground(bkgd:Boolean):void
		{
			this._hasBackground = bkgd;
			redrawBackground();
		}
		
		public function set backgroundAlpha(al:Number):void
		{
			this._backgroundAlpha = al;
			if (this._hasBackground)
				this.redrawBackground();
		}
		
		public function get backgroundAlpha():Number { return this._backgroundAlpha; }
		
		public function get backgroundfilters():Array { return this._backgroundFilters; }
		public function set backgroundfilters(arr:Array) 
		{ 
			this._backgroundFilters = arr;
			this.redrawBackground(); 
		}
		
		public function set backgroundColor(clr:Number):void
		{
			this._backgroundColor = clr;
			if (this._hasBackground)
				this.redrawBackground();
		}
		
		public function get backgroundColor():Number { return this._backgroundColor; }
		
		public function set backgroundOutlineColor(clr:Number):void
		{
			this._backgroundOutlineColor = clr;
			if (this._hasBackground)
				this.redrawBackground();
		}
		
		public function get backgroundOutlineColor():Number { return this._backgroundOutlineColor; }
		
		public function set backgroundOutlineAlpha(clr:Number):void
		{
			this._backgroundOutlineAlpha = clr;
			if (this._hasBackground)
				this.redrawBackground();
		}
		
		public function get backgroundOutlineAlpha():Number { return this._backgroundOutlineAlpha; }
		
		public function set backgroundOutlineThickness(thick:Number):void
		{
			this._backgroundOutlineThickness = thick;
			if (this._hasBackground)
				this.redrawBackground();
		}
		
		public function get backgroundOutlineThickness():Number { return this._backgroundOutlineThickness; }
		
		public function set backgroundType(bt:String):void
		{
			switch (bt)
			{
				case SuperText.BACKGROUND_ADVANCED:
				this._backgroundType = bt;
					redrawBackground();
				break;
				
				case SuperText.BACKGROUND_NORMAL:
				default:
				this._backgroundType = SuperText.BACKGROUND_NORMAL;
					redrawBackground();
				break;
			}
		}
		
		public function get backgroundType():String
		{
			return this._backgroundType;
		}
		
		
		public function set bold(bd:Boolean):void
		{
			this._textFormat.bold = bd;
			redraw();
		}
		
		
		private function clearBackgrounds():void
		{
			if (this.contains(background_mc))
			{
				background_mc.graphics.clear();
				this.removeChild(background_mc);
			}
			
			_textField.background = false;
		}
		
		
		
		private function drawAdvancedBackground():void
		{
			this.clearBackgrounds();
			background_mc.graphics.clear();
			background_mc.graphics.beginFill(this._backgroundColor, this._backgroundAlpha);
			
			if (this._backgroundOutlineAlpha > 0)
			{
				background_mc.graphics.lineStyle(this._backgroundOutlineThickness, this._backgroundOutlineColor, this._backgroundOutlineAlpha);
			}
			else
			{
			}	
			var tempRectangle:Rectangle = new Rectangle(_textField.getBounds(this).x-2, _textField.getBounds(this).y-8, _textField.getBounds(this).width+4, _textField.getBounds(this).height+10);
			
			background_mc.graphics.drawRect(tempRectangle.x, tempRectangle.y, tempRectangle.width, tempRectangle.height);
			background_mc.graphics.endFill();
			background_mc.filters = this._backgroundFilters;
			
			this.addChildAt(background_mc, 0);
		}
		
		private function drawNormalBackground():void
		{
			this.clearBackgrounds();
			_textField.background = true;
			_textField.backgroundColor = this._backgroundColor;
		}
		
		public function selectAll():void
		{
			_textField.setSelection(0, _textField.length);
		}
		
		public function set editable(edit:Boolean):void
		{
			if (edit)
				_textField.type = TextFieldType.INPUT;
			else
				_textField.type = TextFieldType.DYNAMIC;	
		
			this.redraw();
		}
		
		public function set font(fontName:String):void 
		{
			this._textFormat.font = fontName;
			_textField.embedFonts = true;			
			redraw();
		}
		
		public function set fontColor(fontColor:Number):void
		{
			this._textFormat.color = fontColor;
			redraw();
		}
		
		public function set fontSize(fontSize:Number):void
		{
			this._textFormat.size = fontSize;
			redraw();
		}
		
		
		
		public function set htmlText(htmlStr:String):void 
		{ 
			_textField.htmlText = htmlStr; 
			redraw();
		}
		
		public function get htmlText():String { return _textField.htmlText; }
		
		public function set text(str:String):void 
		{ 
			_textField.text = str; 
			redraw();
		}
		public function get text():String { return _textField.text; }
		
		
		public function set interactive(isInter:Boolean):void 
		{
			this._isInteractive = isInter;
			this.mouseEnabled = isInter;
			this.useHandCursor = isInter;
			this.buttonMode = isInter;
			this.mouseChildren = isInter;
		}
		
		public function get interactive():Boolean { return this._isInteractive; } 
		
		public function set multiline(multi:Boolean):void
		{
			_textField.multiline = multi;
		}
		
		public function get multiline():Boolean { return _textField.multiline; }
		
		
		public function set italic(it:Boolean):void
		{
			this._textFormat.italic = it;
			redraw();
		}
		
		public function set sharpness(sharp:Number):void
		{
			_textField.antiAliasType = SuperText.ANTI_ALIAS_ADVANCED;
			_textField.sharpness = sharp;
		}
		
		public function get sharpness():Number { return _textField.sharpness; }
		
		
		public function set thickness(thick:Number):void
		{
			_textField.antiAliasType = SuperText.ANTI_ALIAS_ADVANCED;
			_textField.thickness = thick;
		}
		
		public function get thickness():Number { return _textField.thickness; }
		
		
		public function set selectable(sel:Boolean) { _textField.selectable = sel; } 
		public function get selectable():Boolean { return _textField.selectable; }
		
		public function get selectedText():String { return _textField.selectedText; }
		
		public function set selectionTextFormat(tFormat:TextFormat):void
		{
			_textField.setTextFormat(tFormat, _textField.selectionBeginIndex, _textField.selectionEndIndex);	
		}
		
		public function get selectionTextFormat():TextFormat 
		{
			return _textField.getTextFormat(_textField.selectionBeginIndex, _textField.selectionEndIndex);
		}
		
		public function set textFormat(textFormat:TextFormat):void
		{
			_textFormat = textFormat; 
			redraw(); 
		}
		
		public function get textFormat():TextFormat { return _textFormat; }
		
		public function set autoScroll(autos:Boolean) 
		{
			_autoScroll = autos;
			redraw();
			
		}
		public function get autoScroll():Boolean { return _autoScroll; }
		
		
		public function set wordWrap(wrap:Boolean) { _textField.wordWrap = wrap; }
		public function get wordWrap():Boolean { return _textField.wordWrap; }
		
		
		
	}
}